package jp.sourceforge.talisman.csvio;

/*
 * $Id: CsvLineWriter.java,v 1.1 2009/09/12 05:06:12 weiwei Exp $
 */

import java.io.FilterWriter;
import java.io.IOException;
import java.io.Writer;

/**
 * Write CsvLine object to given output stream.
 *
 * @author Haruaki Tamada
 * @version $Revision: 1.1 $ $Date: 2009/09/12 05:06:12 $
 */
public class CsvLineWriter extends FilterWriter{
    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    private CsvIOSetting setting;

    /**
     * constructor with defualt I/O setting.
     */
    public CsvLineWriter(Writer out){
        super(out);
        this.setting = new CsvIOSetting();
    }

    /**
     * constructor with given I/O setting.
     */
    public CsvLineWriter(Writer out, CsvIOSetting setting){
        super(out);
        this.setting = setting;
    }

    /**
     * returns output setting.
     */
    public CsvIOSetting getSetting(){
        return setting;
    }

    /**
     * sets output setting.
     */
    public void setSetting(CsvIOSetting setting){
        this.setting = setting;
    }

    /**
     * write given CsvLine into target stream with line separator.
     */
    public void write(CsvLine line) throws IOException{
        boolean first = true;
        for(String string: line){
            if(!first){
                super.write(getSetting().getSeparator());
            }
            writeElement(string);
            first = false;
        }
        writeString(LINE_SEPARATOR);
    }

    /**
     * write CsvLine element.
     */
    private void writeElement(String element) throws IOException{
        CsvIOSetting setting = getSetting();
        QuotationMode mode = setting.getQuotationMode();
        EscapeMode escape = setting.getEscapeMode();
        boolean quote = (mode == QuotationMode.ALWAYS);
        char qb = setting.getQuoteBegin();
        char qe = setting.getQuoteBegin();
        String ec = String.valueOf(setting.getEscapeCharacter());

        if(mode == QuotationMode.AS_NEEDED){
            quote = element.indexOf(setting.getSeparator()) >= 0;
        }

        if(escape == EscapeMode.ESCAPE_CHARACTER){
            if(ec.equals("\\")){
                ec = "\\\\";
            }
            element = element.replaceAll(String.valueOf(ec), ec + ec);
            element = element.replaceAll(String.valueOf(qb), ec + qb);
            if(qb != qe){
                element = element.replaceAll(String.valueOf(qe), ec + qe);
            }
        }
        else if(escape == EscapeMode.DOUBLE_CHARACTER){
            element = element.replaceAll(String.valueOf(qb), new String(new StringBuilder().append(qb).append(qb)));
            if(qb != qe){
                element = element.replaceAll(String.valueOf(qe), new String(new StringBuilder().append(qe).append(qe)));
            }
        }

        if(quote){
            element = setting.getQuoteBegin() + element + setting.getQuoteEnd();
        }
        writeString(element);
    }

    /**
     * write string into target stream.
     */
    private void writeString(String string) throws IOException{
        char[] c = string.toCharArray();
        for(int i = 0; i < c.length; i++){
            super.write(c[i]);
        }
    }
}
